import { CostKeys } from "GameLoop/Path/PathFinderManager";
import { StationNetwork } from "GameLoop/Path/StationNetwork";
 
 
import { ShardCommunication } from "GameLoop/ShardCommunication/ShardCommunication";
import { dangrous_style, MoveTips } from "utils/constants/globalconstant";
import { positiveDirections } from "utils/constants/moveConstant";
import { cpu_used } from "utils/decorate/decorate";
import { PositionHelper } from "utils/position/PositionHelper";
import { UtilsHelper } from "utils/position/UtilsHelper";
import { crawlTo } from "./single_creep/path";


/**测试寻路。需要优化
 * 寻路。每次只寻当前房间的路.(好像不能适用与小队寻路，因为小队跨房间，会在边界反复横跳)
 * 寻路设置最大房间数量为1。避免固定站点寻路导致多余的移动。要不然就一次寻路到位(就会存在视野问题导致避开不了NPC)
 */

const swaproles = new Set<RoleName>(["porter",'porter_w'])
 
export interface ICrossMyCreep
{
    (creep:TMove,front:TMove):boolean|ERR_TIRED
}

/**
 * 避让移动
 * 对穿,避让,交头接耳
 * @param creep 发起移动的爬
 * @param front 需要避让的爬
 * @returns 
 */
export function avoidAnyMove (creep:TMove,force=false):boolean
{
    const poss = creep.pos.getFreeSpace(1);
    for(const e of poss)
    {
        if(creepCanbeMove( creep,creep.pos.getDirectionTo(e)))
        {
            creep.move(  creep.pos.getDirectionTo(e),1)
            return true
        }
    }
    return false
}
function getPreDirection(creep:TMove)
{
    if(creep.memory.prePos)
    {
        const ret = creep.memory.prePos.split('/');
        if(ret.length ==2)
        {
            const direction = PositionHelper.getDirection({x:parseInt(ret[0]),y:parseInt(ret[1])},creep.pos);
            return direction
        }
    }
    return 0
} 
function creepCanMove(creep:TMove,dir:DirectionConstant)
{
    if((creep as Creep).fatigue)
    {
        return ERR_TIRED;
    }
 
    const frontpos = creep.pos.directionToPos(dir);
    if(frontpos)
    {
        return posCanMove(creep.room!,frontpos)
    }
    return ERR_TIRED; 
}

function posCanMove(room:Room,frontpos:RoomPosition)
{
   
    if(room.getTerrain().get(frontpos.x, frontpos.y) == TERRAIN_MASK_WALL)
    {
        return ERR_INVALID_TARGET;
    }
    const sites = frontpos
    .lookFor(LOOK_CONSTRUCTION_SITES)
    .filter(
        (e) =>
            e.my &&
            e.structureType !== STRUCTURE_ROAD &&
            e.structureType !== STRUCTURE_CONTAINER &&
            e.structureType !== STRUCTURE_RAMPART,
    )
    if(sites.length>0)
    {
        return ERR_INVALID_TARGET;
    }

    if( frontpos
        .lookFor(LOOK_STRUCTURES)
        .filter(
            (e) =>
                e.structureType !== STRUCTURE_ROAD 
                &&
                !(e.structureType == STRUCTURE_RAMPART &&(e as OwnedStructure).my)
                &&
                e.structureType !== STRUCTURE_CONTAINER 
                &&e.structureType !==STRUCTURE_PORTAL
                ,
        ).length)
    {
        return ERR_INVALID_TARGET;
    }
    return OK;
    
    
}
export function creepCanbeMove(creep:TMove,dir:DirectionConstant)
{
    const frontpos = creep.pos.directionToPos(dir);
    if(frontpos)
    {
        const code = creepCanMove(creep,dir);
        if(code !== OK  )
        {
            return false
        }
        const fontCreep = frontpos.lookMyCreep() || frontpos.lookFor(LOOK_POWER_CREEPS)[0];
        if(fontCreep)
        {
            return false;
        }
        return true;
    }
    return false;
}
 
/**
 * 移动拓展. 分段式寻路，和跨shard 移动
 */
type TMove = (PowerCreep|Creep);
// /*@profile*/
export   class  MoveExtension
{
    // 对穿回调函数
 
    // /**
    //  * 三段式移动。
    //  * 1.第一段确定星门
    //  * 2.第二段确定本shard的房间route
    //  * 3.第三段确定两个相邻房间的移动path
    // */
    
    /**
     * 跨shard移动
     * @param creep
     * @param goal
     */
    public static crossshardMoveTo(creep:Creep,goal:IMoveGoal,opt:IPathFinderOpt)
    {
        if(! creep.memory.shardPath)
        {
            const shardPath =  StationNetwork.getInstance.findPortalRoute({shard:Game.shard.name,room:creep.pos.roomName},{shard:goal.shard?goal.shard:Game.shard.name,room:goal.pos.roomName});
            creep.memory.shardPath = shardPath;
        }
        if(creep.room.name == creep.ownerRoom().name && !creep.room.isSafe())
        {
            opt.IsUseSafeRegion = true;
        }
        const c_mem = creep.memory 

        // 本shard移动完了,检查跨shard星门路由
        ////!!!!*****星门移动 这里要重新写
        if( !c_mem._route || c_mem._route.value.length)
        {
            if(c_mem.shardPath && c_mem.shardPath.value.path.length>0)
            {
                if(UtilsHelper.IsEqualShardRoom(creep.pos,c_mem.shardPath.value.path[0]))
                {
                    // 抵达目标房间
                    // 进行下一次寻路
                    // creepmemory.Debug[`${JSON.stringify(creepmemory.shardroute.path[0])}`] = `抵达:${JSON.stringify(creep.pos)}`;
                    c_mem.shardPath.value.path.splice(0,1);
                }
            }
        }
        else
        {

        }

        if(c_mem.shardPath &&  c_mem.shardPath.value.path.length>0)
        {
            const portalpath  = c_mem.shardPath.value.path[0];
            if(portalpath.roomposition)
            {
                const roomposition = portalpath.roomposition;
                const goalpos =PositionHelper.New(roomposition.x,roomposition.y,roomposition.roomname) as RoomPosition;

                if(goalpos.distance(creep.pos)<=1 && portalpath.roomposition.shard!= portalpath.shard)
                {
                    // 是kuashard星门.跨越星门前要等到数据传输完成。才能跨进去
                    if(!creep.memory.taskid ||ShardCommunication.IsMessageReady(portalpath.shard as shards,creep.memory.taskid))
                    {
                        return this.shardMoveTo(creep,{pos:goalpos,range:0} ,opt);
                    }
                    else
                    {
                        ShardCommunication.SendCreepTask(portalpath.shard as shards,{},creep);
                    }

                }
                else
                {
                    return  this.shardMoveTo(creep,{pos:goalpos,range:0},opt );
                }

            }
            else
            {

                const goalpos =  PositionHelper.New(25,25,portalpath.room) as RoomPosition;;
                return this.shardMoveTo(creep,{pos:goalpos,range:0},opt );
            }
        }
        else
        {
            // 抵达目的地,kuashard寻路完成。开始执行最后的移动抵达目的地
            return this.shardMoveTo(creep,goal ,opt);
        }
        return ERR_INVALID_TARGET
    }

    /**
     * 本shard的移动,
     */
      // @cpu_used()
    
    public static  shardMoveTo(creep:TMove,goal:IMoveGoal,opt:IPathFinderOpt)
    {   
        if(PositionHelper.Distance(creep.pos,goal.pos)<=goal.range)
        {
            // 已经抵达目的地
            creep.memory._move=undefined
            
            return 1;
        }
        const cpu1 = Game.cpu.getUsed()
        if(!creep.memory._route)
        {
            const roompath =  StationNetwork.getInstance.findRoute(creep.pos.roomName,goal.pos.roomName);
            if(roompath)
            {
                creep.memory._route ={key:roompath.key,value:_.clone(roompath.value.route)};
            }
            else
            {
                // 抛出异常，寻不到路
                global.Log.Warning(`mvoeto ${JSON.stringify(goal)} 找不到route`);
                return ERR_NO_PATH
            }
        }
        const cpu2 = Game.cpu.getUsed()
        let tmpopt = _.clone(opt);
        tmpopt.route = creep.memory._route.value
        const code =  crawlTo(creep,goal,tmpopt);
        const cpu3 = Game.cpu.getUsed()
        creep.memory.Debug['move']=cpu3-cpu1
        creep.memory.Debug['route']=cpu2-cpu1
        return code;
    }
    
    /**
     * 逃跑移动
     * @param target 目标位置
     * @param range 安全距离
     * @param ExcludePosition
     * @returns
     */
    public static flee(creep:TMove ,arg:{ pos: RoomPosition, range: number }[], opt:IPathFinderOpt ): void
    {
        if ( arg.every(e=> creep.pos.distance(e.pos)>=e.range)) return //若已逃离目标范围则直接返回

        let path = PathFinder.search(creep.pos,arg, {
            plainCost: 1,
            swampCost:opt.PathCost?.swampCost?opt.PathCost?.swampCost :20,
            maxOps: 100,
            flee: true,
            roomCallback:roomName => {
            
                if ( StationNetwork.getInstance.AvoidRoom &&  StationNetwork.getInstance.AvoidRoom[roomName])
                {
                    return false
                }
                // 在爬虫记忆绕过房间列表的房间 false
                const room = Game.rooms[roomName]
                // 没有视野的房间只观察地形
                if (!room) return true
                // 有视野的房间
                let costs = new PathFinder.CostMatrix
                // 将道路的cost设置为1，无法行走的建筑设置为255
                room.find(FIND_STRUCTURES).forEach(struct => {
                    if (struct.structureType === STRUCTURE_ROAD) {
                        costs.set(struct.pos.x, struct.pos.y, 1)
                    }
                    else if (struct.structureType !== STRUCTURE_CONTAINER &&
                        (struct.structureType !== STRUCTURE_RAMPART || !struct.my))
                        costs.set(struct.pos.x, struct.pos.y, 0xff)
                    })
                room.find(FIND_MY_CONSTRUCTION_SITES).forEach(cons => {
                    if (cons.structureType != 'road' && cons.structureType != 'rampart' && cons.structureType != 'container')
                        costs.set(cons.pos.x, cons.pos.y, 255)
                })
                /* 防止撞到其他虫子造成堵虫 */
                const cache = room.getWorld().PollHostiles(room.name);
                let healVal=1;
                if((creep as Creep).getAbilityHeal)
                {
                    healVal = (creep as Creep).getAbilityHeal();
                }
               
                if(opt.IsBlockExits)
                {
                    const exits =  Game.map.describeExits(roomName);
                    for(let k in exits)
                    {
                        const exitposs = PositionHelper.getExitPositions(roomName,k as ExitKey);
                        for(const es of exitposs)
                        {
                            for(const p of es)
                            {
                                costs.set(p.x,p.y,0xff);
                                
                            }
                        }
                    }
                }
                if(cache)
                {
                    for(let x in cache.hostileDamageMap)
                    {
                        for(let y in cache.hostileDamageMap[x])
                        {
                            if(cache.hostileDamageMap[x][y] > healVal)
                            {
                                costs.set(parseInt(x), parseInt(y), 128)
                            }
                            else 
                            {
                                costs.set(parseInt(x), parseInt(y), cache.hostileDamageMap[x][y]/healVal*128)
                            }
                        }
                    }
                }
               
                
                return costs
            }
        })
        creep.room?.visual.poly(path.path, { stroke: '#ff0000', strokeWidth: 0.15, opacity: 0.1 })
        var direction = creep.pos.getDirectionTo(path.path[0])
        if (!direction) return
        creep.move(direction,creep.crossLevel() );
    }
 
}
